package com.webserver.core;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * 用于处理客户端的交互
 * 遵循HTTP协议与客户端的交互规则为一问一答,因此这里处理分为三步:
 * 1.解析请求
 * 2.处理请求
 * 3.响应客户端
 * 断开连接.
 */
public class ClientHandler implements Runnable {
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        try {
            //第一步:解析请求

            //1.1解析请求行
            String line = readLine();
            System.out.println("请求行:" + line);

            //将读取到的请求行内容的三部分分别赋值给下面三个变量
            String method;//保存请求行中的请求方式
            String uri;//保存抽象路径
            String protocol;//保存协议版本
            String[] data = line.split("\\s");//按照空格拆分
            method = data[0];
            uri = data[1];
            protocol = data[2];
            System.out.println("method:" + method);
            System.out.println("uri:" + uri);
            System.out.println("protocol:" + protocol);

            /*
                循环读取每一行字符串,每一行是一个消息头.读取后输出到控制台
                单独读取到CRLF停止循环
                输出格式:
                消息头:Connection:keep-alive
                消息头:...
                ...
             */

            //1.2解析消息头
            //key消息头的名字,value消息头对应的值
            Map<String,String> headers = new HashMap<>();
            while (true){
                line = readLine();
                if (line.isEmpty()){//判断是否为空字符串,是的话说明读到了CRLF
                    break;
                }
                System.out.println("消息头:"+line);
                String[] s = line.split(":\\s");
                headers.put(s[0],s[1]);
            }
            System.out.println(headers);
            //1.3解析消息正文(暂时不处理)

            //第二步:处理请求

            //第三步:响应客户端

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //交互完毕后断开连接(协议要求)
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private String readLine() throws IOException {
        /*
            InputStream get InputStream
            该方法获取的输入流用于读取远端计算机发送过来的数据.
            注意:Socket不变的前提下,无论调用多少次该方法,返回的输入流始终是同一个流.
         */
        InputStream in = socket.getInputStream();
        int d;
        char pre = 'a';//记录上次读取的字符内容
        char cur;      //记录本次读取的字符内容
        StringBuilder builder = new StringBuilder();
        while ((d = in.read()) != -1) {
            cur = (char) d;
            if (pre == 13 && cur == 10) {
                break;
            }
            builder.append(cur);
            pre = cur;//将本次读取的字符内容在下次循环时记录在上次读取的字符
        }
        return builder.toString().trim();
    }
}
